#include <protocolProcesser.h>

// // check head: version, crypte
// static uint16_t protocolParsePretreatCommon(struct protocolProcessorInform *devider, void *packdata, uint32_t packsize)
// {
//     struct protocolPackageCommonInform *tmpprotocol = (struct protocolPackageCommonInform *)packdata;
//     if (!tmpprotocol)
//     {
//         logerror("");
//         return -1;
//     }
//     if (!devider)
//     {
//         logerror("");
//         return -1;
//     }
//     if (tmpprotocol->protocolVersion != protocolParseCommonVersion2)
//     {
//         logerror("%d", tmpprotocol->protocolVersion);
//         return -1;
//     }
// #if COMMAND_PROTOCOL_USE_ADDR
//     if (tmpprotocol->pv2.v2DestinationAddr == PROTOCOL_BROADCAST_485ADDRESS)
//     {
//     }
//     else if (tmpprotocol->pv2.v2DestinationAddr != devider->communicateInform.my485Addr)
//     {
//         logerror("command dev addr:%d, my addr:%d", tmpprotocol->pv2.v2DestinationAddr, devider->communicateInform.my485Addr);
//         return -1;
//     }
// #endif
//     if (tmpprotocol->pv2.v2DataCrypteType != protocolParseCrypte_None)
//     {
//         logerror("%d", tmpprotocol->pv2.v2DataCrypteType);
//         return -1;
//     }
//     if (tmpprotocol->pv2.v2DataSize < offsetof(struct commandCommonStruct, commandData))
//     {
//         logerror("parse:%d", tmpprotocol->pv2.v2DataSize);
//         return -1;
//     }
//     struct commandCommonStruct *tmpCommand = (struct commandCommonStruct *)tmpprotocol->pv2.v2Data;
//     return tmpCommand->command;
// }

// static uint16_t protocolPackageWithCommand(void *outPack, uint16_t outsize)
// {
//     struct protocolPackageCommonInform *tmppack = (struct protocolPackageCommonInform *)outPack;
//     struct commandCommonStruct *tmpcommand;
//     if (!outPack)
//     {
//         logerror("");
//         return 0;
//     }
//     if ((PROTOCOL_V2_COMMAND_HEAD_SIZE + tmppack->pv2.v2DataSize) > outsize)
//     {
//         logerror("data big:%d", tmppack->pv2.v2DataSize);
//         return 0;
//     }
//     tmppack->pv2.v2SourceAddr
//     return protocolPackageDataV2(outPack, outsize);
// }

// protocol parse finish, and check
static void protocolParseProcessorCallback(void *packdata, uint32_t packsize, void *userdata)
{
    struct protocolProcessorInform *tmpProcesser = (struct protocolProcessorInform *)userdata;
    struct protocolPackageCommonInform *tmpprotocol = (struct protocolPackageCommonInform *)packdata;
    struct commandCommonStruct *tmpCommonCmd = (struct commandCommonStruct *)tmpprotocol->pv2.v2Data;
    uint16_t tmpCommandID;
    int tmpflag = 0;
    if (!tmpProcesser || !packdata)
    {
        logerror("");
        return;
    }

    if (tmpprotocol->protocolVersion != protocolParseCommonVersion2)
    {
        logerror("%d", tmpprotocol->protocolVersion);
        return;
    }
    if (tmpprotocol->pv2.v2DestinationAddr == PROTOCOL_BROADCAST_485ADDRESS)
    {
    }
    else if (tmpprotocol->pv2.v2DestinationAddr != tmpProcesser->communicateInform.my485Addr)
    {
        // logerror("command dev addr:%d, my addr:%d", tmpprotocol->pv2.v2DestinationAddr, tmpProcesser->communicateInform.my485Addr);
        return;
    }
    if (tmpprotocol->pv2.v2DataCrypteType != protocolParseCrypte_None)
    {
        logerror("%d", tmpprotocol->pv2.v2DataCrypteType);
        return;
    }
    if (tmpprotocol->pv2.v2DataSize < PROTOCOL_COMMAND_COMMON_HEAD_SIZE)
    {
        logerror("parse:%d", tmpprotocol->pv2.v2DataSize);
        return;
    }
    tmpCommandID = tmpCommonCmd->command;
    // tmpCommandID = protocolParsePretreatCommon(tmpProcesser, packdata, packsize);
    tmpflag = hashCommandActuatorRun(&tmpProcesser->protocolCommandMng, tmpCommandID, packdata, &packsize);

#if COMMAND_MASTER_CALL_DEFINE
    if (tmpProcesser->communicateInform.my485Addr == 0)
    {
        if (tmpCommonCmd->command != tmpProcesser->commandExcuter.command)
        {
            logerror("command %d != %d", tmpCommonCmd->command, tmpProcesser->commandExcuter.command);
            return;
        }
        if (tmpCommonCmd->serialNumber != tmpProcesser->commandExcuter.serialNumber)
        {
            logerror("serial %d != %d", tmpCommonCmd->serialNumber, tmpProcesser->commandExcuter.serialNumber);
            return;
        }
        tmpProcesser->commandExcuter.responseFlag = tmpCommonCmd->responseFlag;
    }
    else
#endif
    {
        if (tmpflag < 0)
        {
            logerror("");
            return;
        }
        else if(tmpCommonCmd->command == 0 || tmpCommonCmd->command == 1)
        {
        }
        else if (tmpprotocol->pv2.v2DestinationAddr == PROTOCOL_BROADCAST_485ADDRESS)
        {
            logdebug("not surpport broadcast");
            return;
        }
        tmpCommonCmd->responseFlag = tmpflag;
        tmpprotocol->pv2.v2DataSize = PROTOCOL_V2_DATA_SIZE(packsize);
        protocolCommandPackAndSend(tmpProcesser, packdata, PROTOCOL_PACK_MAX_SIZE);
    }
}

void protocolProcessorInit(struct protocolProcessorInform *devider, struct protocolCommandCommunicateInform setCommuni,
                           struct hashCommandActuatorManage setHashActor)
{
    int i;
    if (!devider)
    {
        logerror("");
        return;
    }
    if (!setHashActor.commandHash || setHashActor.hashSize < 1)
    {
        logerror("");
        return;
    }
    if (!setCommuni.receiveFunction || !setCommuni.sendFunction)
    {
        logerror("");
        return;
    }
    devider->communicateInform = setCommuni;
    devider->protocolCommandMng = setHashActor;
    logdebug("%d, %p", devider->communicateInform.my485Addr, devider);
    for (i = 0; i < setHashActor.hashSize; i++)
    {
        setHashActor.commandHash[i].userdata = devider;
    }
    protocolPackageParseInit(&devider->parser, protocolParseProcessorCallback, devider, devider->parsePackBuffer, sizeof(devider->parsePackBuffer));
#if COMMAND_MASTER_CALL_DEFINE
    devider->commandExcuter = (struct commandCommonStruct){0};
#endif
}

void protocolProcessorRunReceive(struct protocolProcessorInform *devider)
{
    int tmpreadsize, i;
    uint8_t tmpreadbuffer[32];
    if (!devider)
    {
        logerror("");
        return;
    }
    if (!devider->communicateInform.receiveFunction)
    {
        logerror("");
        return;
    }
    do
    {
        tmpreadsize = devider->communicateInform.receiveFunction(tmpreadbuffer, sizeof(tmpreadbuffer), devider->communicateInform.userdata);
        if (!(tmpreadsize > 0 && tmpreadsize <= sizeof(tmpreadbuffer)))
        {
            // logdebug("%d", tmpreadsize);
            break;
        }
        // logdebug("addr=%d, read size=%d", devider->communicateInform.my485Addr, tmpreadsize);
        for (i = 0; i < tmpreadsize; i++)
        {
            protocolPackageParseValue(&devider->parser, tmpreadbuffer[i]);
        }
    } while (1);
}

uint16_t processerPackageProtocolData(struct protocolProcessorInform *processer, uint8_t *outpack, uint32_t outsize)
{
    struct protocolPackageCommonInform *tmppack = (struct protocolPackageCommonInform *)outpack;
    if (!processer || !outpack )
    {
        logerror("");
        return 0;
    }
    if ((PROTOCOL_V2_COMMON_HEAD_SIZE + tmppack->pv2.v2DataSize) > outsize)
    {
        logerror("data big:%d", tmppack->pv2.v2DataSize);
        return 0;
    }
    // logdebug("%d", processer->communicateInform.my485Addr);
#if COMMAND_MASTER_CALL_DEFINE
    if (processer->communicateInform.my485Addr == 0)
    {
        tmppack->pv2.v2SourceAddr = processer->communicateInform.my485Addr;
        tmppack->pv2.v2DestinationAddr = processer->commandExcuterAddr;
    }
    else
#endif
    {
        SWAP_BASE_VAL(tmppack->pv2.v2SourceAddr, tmppack->pv2.v2DestinationAddr);
    }
    tmppack->pv2.v2DataCrypteType = protocolParseCrypte_None;
    tmppack->pv2.v2DataCompressType = 0;
    tmppack->pv2.v2DataType = 0;
    // setcommand->addr485 = processer->communicateInform.my485Addr;
    return protocolPackageDataV2(outpack, outsize);
}

uint16_t processerSendProtocolData(struct protocolProcessorInform *processer, uint8_t *outpack, uint32_t outsize)
{
    if (!processer || !outpack)
    {
        logerror("");
        return 0;
    }
    if (!processer->communicateInform.sendFunction)
    {
        logerror("");
        return 0;
    }
    return processer->communicateInform.sendFunction(outpack, outsize, processer->communicateInform.userdata);
}

uint16_t protocolCommandPackAndSend(struct protocolProcessorInform *processer, uint8_t *outpack, uint32_t outsize)
{
    uint16_t tmpPackSize = processerPackageProtocolData(processer, outpack, outsize);
    if (tmpPackSize < 1)
    {
        logerror("");
        return 0;
    }
    return processerSendProtocolData(processer, outpack, tmpPackSize);
}
#if COMMAND_MASTER_CALL_DEFINE
uint16_t generateCommandSerial()
{
    static uint16_t genseial = 0;
    return genseial++;
}
int masterProcesserSetReTryCount(struct protocolProcessorInform *processer, uint8_t setRetry)
{
    if (!processer)
    {
        logerror("");
        return -1;
    }
    processer->communicateInform.retryMaxTime = LIMIT_VAL(setRetry, 0, 5);
    return 0;
}
int masterProcesserSetTimeout(struct protocolProcessorInform *processer, uint32_t setTimeoutMs)
{
    if (!processer)
    {
        logerror("");
        return -1;
    }
    processer->communicateInform.commandWaitTimeoutMs = LIMIT_VAL(setTimeoutMs, PROTOCOL_MIN_WAIT_TIMEOUT_MS, PROTOCOL_MAX_WAIT_TIMEOUT_MS);
    return 0;
}
int masterCommandProcesserState(struct protocolProcessorInform *devider)
{
    if (!devider)
    {
        logerror("");
        return commandExcuteResultUnkown;
    }
    return (int)(int16_t)devider->commandExcuter.responseFlag;
}
int masterCommandProcesserWaitResponse(struct protocolProcessorInform *processer)
{
    timerMsDefBegin(tmptimer);
    if (!processer)
    {
        logerror("");
        return commandExcuteResultUnkown;
    }
    processer->communicateInform.commandWaitTimeoutMs = LIMIT_VAL(processer->communicateInform.commandWaitTimeoutMs,
                                                                  PROTOCOL_MIN_WAIT_TIMEOUT_MS, PROTOCOL_MAX_WAIT_TIMEOUT_MS);
    do
    {
        protocolProcessorRunReceive(processer);
        if (masterCommandProcesserState(processer) != commandExcuteResultUnkown)
        {
            break;
        }
        usleep(10 * 1000);
    } while (timerMsRunMs(tmptimer) < processer->communicateInform.commandWaitTimeoutMs);
    return masterCommandProcesserState(processer);
}
int masterProcesserSendAndWaitResponse(struct protocolProcessorInform *processer, void *sendData, uint32_t sendSize)
{
    int tmpflag = 0;
    int8_t tmpRetryCount = 0;
    if (!processer)
    {
        logerror("");
        return commandExcuteResultUnkown;
    }
    processer->communicateInform.retryMaxTime = LIMIT_VAL(processer->communicateInform.retryMaxTime, 0, 5);
    do
    {
        processerSendProtocolData(processer, sendData, sendSize);
        tmpflag = masterCommandProcesserWaitResponse(processer);
        if (tmpflag != commandExcuteResultUnkown)
        {
            break;
        }
    } while (tmpRetryCount++ < processer->communicateInform.retryMaxTime);
    return tmpflag;
}
#endif